package cn.darkhorse.mesadmin.controller.wechat;

import cn.darkhorse.meswechat.common.WxChatCommon;
import cn.darkhorse.meswechat.config.WxPayConfig;
import cn.darkhorse.meswechat.service.IWeChatCallBackService;
import cn.darkhorse.meswechat.util.WXPayUtility;
import cn.darkhorse.pick.pojo.PickOrder;
import cn.darkhorse.pick.pojo.PickOrderPay;
import cn.darkhorse.pick.service.PickOrderPayService;
import cn.darkhorse.pick.service.PickOrderService;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.system.service.ISysUserService;

import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.*;
//import com.wechat.pay.java.service.payments.jsapi.NativePayService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@RestController
@RequestMapping("/wechat/common")
public class WechatCommonController extends BaseController {

    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private IWeChatCallBackService weChatCallBackService;
    @Autowired
    private WxPayConfig wxPayConfig;
    @Autowired
    private PickOrderPayService pickOrderPayService;
    @Autowired
    private PickOrderService pickOrderService;

    /**
     * 绑定openid
     */
//    @PostMapping("/bindOpenId")
//    public AjaxResult bindOpenId(String openId) {
//        weChatUserService.wxBindUsers(getUserId(), openId);
//        return AjaxResult.success();
//    }

    @PostMapping("/getInfo")
    @ApiOperation("微信登录")
    public AjaxResult wxLogin(String code) {
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid="+WxChatCommon.APP_ID+"&secret="+WxChatCommon.SECRET+"&js_code="+code+"&grant_type=authorization_code";
        LoginUser loginUser = SecurityUtils.getLoginUser();


        String responseder = HttpUtils.sendGet(url);
        System.out.println("获取响应："+responseder);
        if(StringUtils.isNotBlank(responseder)) {
            JSONObject jsonObject = JSONObject.parseObject(responseder);
            String openId = jsonObject.getString("openid");
            if (loginUser == null){
                SysUser user = SecurityUtils.getLoginUser().getUser();
                user.setOpenId(openId);
                sysUserService.updateUser(user);
            }
            return AjaxResult.success("获取成功",openId);
        }
        return AjaxResult.error();
    }

    @PostMapping("/prePay")
    @ApiOperation("微信预支付")
    public AjaxResult prePay(Long id,String openId) {

        PickOrder pickOrder = pickOrderService.getById(id);
        if (pickOrder.getAmountDue()==null || pickOrder.getAmountDue().compareTo(BigDecimal.ZERO)==0) {
            return AjaxResult.error("非法的支付金额");
        }

        PickOrderPay orderPay = pickOrderPayService.lambdaQuery()
                .eq(PickOrderPay::getOrderNumber, pickOrder.getOrderNumber())
                .eq(PickOrderPay::getPayStatus, 0)
                .one();

        String prepayId = "";
        if (orderPay != null) {
            prepayId = orderPay.getPrePayId();
        }else {
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(WxChatCommon.MCH_ID)
                        .privateKey(wxPayConfig.getPrivateKey("key/apiclient_key.pem"))
//                        .privateKeyFromPath("key/apiclient_key.pem")
                        .merchantSerialNumber(WxChatCommon.MERCHANT_SERIAL_NUMBER)
                        .apiV3Key(WxChatCommon.API_V3_KEY)
                        .build();
            // 构建service

            LocalDateTime now = LocalDateTime.now();

            JsapiService service = new JsapiService.Builder().config(config).build();
            PrepayRequest request = new PrepayRequest();
            request.setAppid(wxPayConfig.getAppid());
            request.setMchid(wxPayConfig.getMchId());
            request.setDescription("采棉机作业费用");
            String outTradeNo = pickOrder.getOrderNumber() + System.currentTimeMillis();
            request.setOutTradeNo(outTradeNo);
            request.setAttach(pickOrder.getId().toString());
            request.setNotifyUrl("http://hm2009.kmras.com:32738/prod-api/wechat/common/payCallBack");
            request.setSupportFapiao(false);
            request.setAmount(new Amount());
            request.getAmount().setTotal(pickOrder.getAmountDue().multiply(BigDecimal.valueOf(100)).intValue());
            request.getAmount().setCurrency("CNY");
            request.setPayer(new Payer());
            request.getPayer().setOpenid(openId);
// 调用下单方法，得到应答
            PrepayResponse response = service.prepay(request);

            PickOrderPay pickOrderPay = new PickOrderPay();
            pickOrderPay.setOrderNumber(pickOrder.getOrderNumber());
            pickOrderPay.setPayNumber(outTradeNo);
            pickOrderPay.setPayAmount(request.getAmount().getTotal());
            pickOrderPay.setPayStatus(0);
            pickOrderPay.setPayUser(pickOrder.getOpenId());
            pickOrderPay.setPayStartTime(now);
            pickOrderPay.setPrePayId(response.getPrepayId());
            pickOrderPayService.save(pickOrderPay);

            pickOrderService.lambdaUpdate()
                    .eq(PickOrder::getId, pickOrder.getId())
                    .set(PickOrder::getPayStartTime, now)
                    .update();
            prepayId = response.getPrepayId();//下单返回的prepayId
        }
        long timestamp = System.currentTimeMillis();//时间戳
        String nonceStr = WXPayUtility.createNonce(32);//随机字符串
        String pack = StringUtils.join("prepay_id=", prepayId);//订单详情扩展字符串
        String paySign = null;
        try {
            paySign = wxPayConfig.getSign(wxPayConfig.getAppid(), timestamp, nonceStr, pack);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        logger.info("paySignpaySignpaySign="+paySign);
        JSONObject data = new JSONObject();
        data.put("appid",wxPayConfig.getAppid());//appid
        data.put("timeStamp",String.valueOf(timestamp));
        data.put("nonceStr",nonceStr);
        data.put("package",pack);
        data.put("signType","RSA");//签名方式
        data.put("paySign",paySign);


        return AjaxResult.success(data);
    }



//
//    @PostMapping("/nativePrePay")
//    @ApiOperation("微信预支付")
//    public AjaxResult nativePrePay(Long id) {
//        PickOrder pickOrder = pickOrderService.getById(id);
//        if (pickOrder.getAmountDue()==null || pickOrder.getAmountDue().compareTo(BigDecimal.ZERO)==0) {
//            return AjaxResult.error("非法的支付金额");
//        }
//        PickOrderPay orderPay = pickOrderPayService.lambdaQuery()
//                .eq(PickOrderPay::getOrderNumber, pickOrder.getOrderNumber())
//                .eq(PickOrderPay::getPayStatus, 0)
//                .one();
//        if (orderPay != null) {
//            PrepayResponse prepayResponse = new PrepayResponse();
//            prepayResponse.setCodeUrl(orderPay.getPrePayId());
//            return AjaxResult.success(prepayResponse);
//        }
//
//
//
//        Config config =
//                new RSAAutoCertificateConfig.Builder()
//                        .merchantId(WxChatCommon.MCH_ID)
//                        .privateKey(wxPayConfig.getPrivateKey("key/apiclient_key.pem"))
////                        .privateKeyFromPath("key/apiclient_key.pem")
//                        .merchantSerialNumber(WxChatCommon.MERCHANT_SERIAL_NUMBER)
//                        .apiV3Key(WxChatCommon.API_V3_KEY)
//                        .build();
//        // 构建service
//
//        LocalDateTime now = LocalDateTime.now();
//
//        NativePayService service = new NativePayService.Builder().config(config).build();
//        PrepayRequest request = new PrepayRequest();
//        request.setAppid(WxChatCommon.APP_ID);
//        request.setMchid(WxChatCommon.MCH_ID);
//        request.setDescription("采棉机作业费用");
//        String outTradeNo = pickOrder.getOrderNumber() + System.currentTimeMillis();
//        request.setOutTradeNo(outTradeNo);
//        request.setAttach(pickOrder.getId().toString());
//        request.setNotifyUrl("http://hm2009.kmras.com:32738/wechat/common/payCallBack");
//        request.setSupportFapiao(false);
//        request.setAmount(new Amount());
//        request.getAmount().setTotal(pickOrder.getAmountDue().multiply(BigDecimal.valueOf(100)).intValue());
//        request.getAmount().setCurrency("CNY");
//// 调用下单方法，得到应答
//        PrepayResponse response = service.prepay(request);
//
//        PickOrderPay pickOrderPay = new PickOrderPay();
//        pickOrderPay.setOrderNumber(pickOrder.getOrderNumber());
//        pickOrderPay.setPayNumber(outTradeNo);
//        pickOrderPay.setPayAmount(request.getAmount().getTotal());
//        pickOrderPay.setPayStatus(0);
//        pickOrderPay.setPayUser(pickOrder.getOpenId());
//        pickOrderPay.setPayStartTime(now);
//        pickOrderPayService.save(pickOrderPay);
//
//        pickOrderService.lambdaUpdate()
//                .eq(PickOrder::getId, pickOrder.getId())
//                .set(PickOrder::getPayStartTime, now)
//                .set(PickOrder::getPayCode, response.getCodeUrl())
//                .update();
//
//        return AjaxResult.success(response);
//    }

    @PostMapping("/payCallBack")
    public Map<String, String> payCallBack(HttpServletRequest request, HttpServletResponse response) throws IOException, GeneralSecurityException {
        //获取报文
        String body = getRequestBody(request);

        //随机串
        String nonceStr = request.getHeader("Wechatpay-Nonce");

        //微信传递过来的签名
        String signature = request.getHeader("Wechatpay-Signature");

        //证书序列号（微信平台）
        String serialNo = request.getHeader("Wechatpay-Serial");

        //时间戳
        String timestamp = request.getHeader("Wechatpay-Timestamp");

        //构造签名串

        //应答时间戳\n
        //应答随机串\n
        //应答报文主体\n
        String signStr = Stream.of(timestamp, nonceStr, body).collect(Collectors.joining("\n", "", "\n"));

        Map<String, String> map = new HashMap<>(2);
        try {
            //验证签名是否通过
            boolean result = verifiedSign(serialNo, signStr, signature);

            if(result){
                //解密数据
                String plainBody = decryptBody(body);
                logger.info("解密后的明文:{}",plainBody);

                Map<String, String> paramsMap = convertWechatPayMsgToMap(plainBody);
                //处理业务逻辑 TODO
                PickOrderPay orderPay = pickOrderPayService.lambdaQuery().eq(PickOrderPay::getPayNumber, paramsMap.get("out_trade_no")).one();
                if(orderPay != null) {
                    orderPay.setPayStatus(1);
                    orderPay.setPayEndTime(LocalDateTime.now());
                    pickOrderPayService.updateById(orderPay);

                    PickOrder pickOrder = pickOrderService.lambdaQuery().eq(PickOrder::getOrderNumber, orderPay.getOrderNumber()).one();
                    if(pickOrder != null) {
                        pickOrder.setStatus(2);
                        pickOrder.setPayTime(orderPay.getPayEndTime());
                        pickOrder.setTransactionId(paramsMap.get("transaction_id"));
                        pickOrder.setPayAmount(new BigDecimal(orderPay.getPayAmount()).divide(new BigDecimal(100)));
                        pickOrderService.updateById(pickOrder);
                    }
                }

                //响应微信
                map.put("code", "SUCCESS");
                map.put("message", "成功");
            }



        } catch (Exception e) {
            logger.error("微信支付回调异常:{}", e);
        }

        return map;
    }

    /**
     * 取消结算
     */
    @PostMapping("/cancel-settlement")
    @ApiOperation(value = "取消结算")
    public AjaxResult cancelSettlement(Long id) {
        PickOrder pickOrder = pickOrderService.getById(id);
        if (pickOrder.getPayStartTime()!=null){
            pickOrder.setPayStartTime( null);

            PickOrderPay orderPay = pickOrderPayService.lambdaQuery().eq(PickOrderPay::getOrderNumber, pickOrder.getOrderNumber())
                    .eq(PickOrderPay::getPayStatus, 0)
                    .one();
            if (orderPay != null){

                Config config =
                        new RSAAutoCertificateConfig.Builder()
                                .merchantId(WxChatCommon.MCH_ID)
                                .privateKeyFromPath("key/apiclient_key.pem")
                                .merchantSerialNumber(WxChatCommon.MERCHANT_SERIAL_NUMBER)
                                .apiV3Key(WxChatCommon.API_V3_KEY)
                                .build();
                JsapiService.Builder serviceBuilder = new JsapiService.Builder();
                JsapiService jsapiService = serviceBuilder.config(config).build();
                CloseOrderRequest orderRequest = new CloseOrderRequest();
                orderRequest.setMchid(WxChatCommon.MCH_ID);
                orderRequest.setOutTradeNo(orderPay.getPayNumber());
                jsapiService.closeOrder(orderRequest);

                orderPay.setPayStatus(2);
                pickOrderPayService.updateById(orderPay);

                pickOrder.setStatus(3);

            }
        }

        return AjaxResult.success(pickOrderService.updateById(pickOrder));
    }

    /**
     * 转换body为map
     * @param plainBody
     * @return
     */
    private Map<String,String> convertWechatPayMsgToMap(String plainBody){

        Map<String,String> paramsMap = new HashMap<>(2);

        JSONObject jsonObject = JSONObject.parseObject(plainBody);

        //商户订单号
        paramsMap.put("out_trade_no",jsonObject.getString("out_trade_no"));

        //交易状态
        paramsMap.put("trade_state",jsonObject.getString("trade_state"));

        //附加数据
        paramsMap.put("account_no",jsonObject.getString("attach"));

        return paramsMap;

    }



    /**
     * 解密body的密文
     *
     * "resource": {
     *         "original_type": "transaction",
     *         "algorithm": "AEAD_AES_256_GCM",
     *         "ciphertext": "",
     *         "associated_data": "",
     *         "nonce": ""
     *     }
     *
     * @param body
     * @return
     */
    private String decryptBody(String body) throws UnsupportedEncodingException, GeneralSecurityException {

        AesUtil aesUtil = new AesUtil(WxChatCommon.API_V3_KEY.getBytes("utf-8"));

        JSONObject object = JSONObject.parseObject(body);
        JSONObject resource = object.getJSONObject("resource");
        String ciphertext = resource.getString("ciphertext");
        String associatedData = resource.getString("associated_data");
        String nonce = resource.getString("nonce");

        return aesUtil.decryptToString(associatedData.getBytes("utf-8"),nonce.getBytes("utf-8"),ciphertext);

    }



    /**
     * 验证签名
     *
     * @param serialNo  微信平台-证书序列号
     * @param signStr   自己组装的签名串
     * @param signature 微信返回的签名
     * @return
     * @throws UnsupportedEncodingException
     */
    private boolean verifiedSign(String serialNo, String signStr, String signature) throws Exception {
        return wxPayConfig.getVerifier().verify(serialNo, signStr.getBytes("utf-8"), signature);
    }


    /**
     * 读取请求数据流
     *
     * @param request
     * @return
     */
    private String getRequestBody(HttpServletRequest request) {

        StringBuffer sb = new StringBuffer();

        try (ServletInputStream inputStream = request.getInputStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        ) {
            String line;

            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        return sb.toString();

    }

}
